#ifndef __KEWINTERNAL_H__
#define __KEWINTERNAL_H__
#ifdef __cplusplus
extern "C" {
#endif

#include <glib.h>
#include <kew.h>
#include <setjmp.h>

/* FIXME: this should be autoconf detected */
#define KEW_STACKED_ABOVE(A,B) (((gpointer)(A)) < ((gpointer)(B)))


extern void Kew__InitException(void);
extern void Kew__InitContinuation(void);
extern void Kew__InitNil(void);
extern void Kew__InitBool(void);
extern void Kew__InitVar(void);
extern void Kew__InitBlock(void);
extern void Kew__InitList(void);
extern void Kew__InitMap(void);
extern void Kew__InitMessage(void);
extern void Kew__InitPrimitives(void);

extern void Kew__GenericHash(KewObject *receiver, KewObject *args[], KewObject *results[]);
extern void Kew__GenericEqual(KewObject *receiver, KewObject *args[], KewObject *results[]);

extern void Kew__NoFinalize(KewObject *object);
extern guint Kew__HashFunction(gpointer object);
extern gint Kew__EqualFunction(gpointer object_a, gpointer object_b);


#define METHOD(NAME) \
static void \
NAME(KewObject *receiver, KewObject *args[], KewObject *results[])


#define kew_continuation_frame(OBJECT) \
  ((struct KewContinuationFrame *)((OBJECT)->context[0]))

struct KewContinuationFrame {
  KewObject *next_continuation;
  sigjmp_buf jump_buffer;
};

extern KewObject *kew_top_continuation;

#define kew_handler_frame(OBJECT) \
  ((struct KewExceptionHandlerFrame *)((OBJECT)->context[0]))
#define kew_default_handler(OBJECT) \
  ((OBJECT)->context[1])

struct KewExceptionHandlerFrame {
  struct KewExceptionHandlerFrame *next;
  struct KewExceptionHandlerFrame *next_on_stack;
  KewObject *block;
  KewObject *exception;
};

extern struct KewExceptionHandlerFrame *kew_top_exception_handler_frame;

/* Types */

extern KewObjectType kew_continuation_type;
extern KewObjectType kew_exception_type;
extern KewObjectType kew_list_type;
extern KewObjectType kew_map_type;

/* Send convenience wrappers */

extern KewObject *_KewSend0(KewObject *receiver,
                            char *selector,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend0(RECEIVER, SELECTOR) \
_KewSend0((RECEIVER), (SELECTOR), SOURCE_FILE_NAME, __LINE__)

extern KewObject *_KewSend1(KewObject *receiver,
                            char *selector,
                            KewObject *arg0,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend1(RECEIVER, SELECTOR, ARG0) \
_KewSend1((RECEIVER), (SELECTOR), (ARG0), SOURCE_FILE_NAME, __LINE__)

extern KewObject *_KewSend2(KewObject *receiver,
                            char *selector,
                            KewObject *arg0,
                            KewObject *arg1,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend2(RECEIVER, SELECTOR, ARG0, ARG1) \
_KewSend2((RECEIVER), (SELECTOR), (ARG0), (ARG1), SOURCE_FILE_NAME, __LINE__)

extern KewObject *_KewSend3(KewObject *receiver,
                            char *selector,
                            KewObject *arg0,
                            KewObject *arg1,
                            KewObject *arg2,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend3(RECEIVER, SELECTOR, ARG0, ARG1, ARG2) \
_KewSend3((RECEIVER), (SELECTOR), (ARG0), (ARG1), (ARG2), SOURCE_FILE_NAME, __LINE__)

extern KewObject *_KewSend4(KewObject *receiver,
                            char *selector,
                            KewObject *arg0,
                            KewObject *arg1,
                            KewObject *arg2,
                            KewObject *arg3,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend4(RECEIVER, SELECTOR, ARG0, ARG1, ARG2, ARG3) \
_KewSend4((RECEIVER), (SELECTOR), (ARG0), (ARG1), (ARG2), (ARG3), SOURCE_FILE_NAME, __LINE__)

extern KewObject *_KewSend5(KewObject *receiver,
                            char *selector,
                            KewObject *arg0,
                            KewObject *arg1,
                            KewObject *arg2,
                            KewObject *arg3,
                            KewObject *arg4,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend5(RECEIVER, SELECTOR, ARG0, ARG1, ARG2, ARG3, ARG4) \
_KewSend5((RECEIVER), (SELECTOR), (ARG0), (ARG1), (ARG2), (ARG3), (ARG4), SOURCE_FILE_NAME, __LINE__)

extern KewObject *_KewSend6(KewObject *receiver,
                            char *selector,
                            KewObject *arg0,
                            KewObject *arg1,
                            KewObject *arg2,
                            KewObject *arg3,
                            KewObject *arg4,
                            KewObject *arg5,
                            char *source_file_name,
                            unsigned line_number);
#define KewSend6(RECEIVER, SELECTOR, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) \
_KewSend6((RECEIVER), (SELECTOR), (ARG0), (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), \
          SOURCE_FILE_NAME, __LINE__)


#ifdef __cplusplus
}
#endif
#endif
